/**
 * The class Polygon represents a polygon using an array of Point data type, where the last point is equal to the first so as to close the polygon
 * If there are two points that are the same and not as described previously, then the segment between them would be considered an unnecessary segment.
 * 
 * @author Michael Fildstein, ID: 309161594     
 * @author Tomer Ben Rachel ID: 021982475     
 */




public class Polygon {
  
  private Point[] points;
  private Point[] actualVertices;
  private double perimeter;
  
  
  /**
   * Constructor that creates a new empty array of Point data type
  */  

  public Polygon(){
    points = new Point[0];
  }
  
  
  /**
   * Constructor that creates a new array of Point data type and copies the points from the array the user inputed
   * @param vertices a Point data type array representing the polygon the user has given us
   * @throws Runtime exception if the point value is null
  */	
  
  
  public Polygon(Point[] points){
	    if (points != null){
	    	this.points = new Point[points.length];
	        for (int i = 0 ; i < points.length ; i++){
	        	if (points[i] instanceof Point){
	        		this.points[i] = points[i];
	        	  }  
	       }
	      this.actualVertices = this.getVerticesPrivate();  //stores the actual Vertices (without duplicates) in the actualVertices field
	      this.perimeter = this.perimiterPrivate();			//stores the perimeter in the perimeter field
	    }else{
	      throw new RuntimeException("vertices value is null");
	    	}    
	  }
  
  /**
   * The method getVertices returns an array of Point data type containing only valid points
   * @return a Point data type array containing points which are not redundant
  */	  

  
  public Point[] getVertices(){
    return this.actualVertices;
  }
  
  /**
   * The private method getVerticesPrivate goes through the array of points and returns a new array of Point data type that contains only the points which show up once
   * @return a Point data type array containing points which are not redundant
  */	  
 
  
  private Point[] getVerticesPrivate(){
    Point[] tempArray = new Point[this.points.length];								
    Point[] ans;
    
    tempArray[0] = this.points[0];										
    int tempIndex = 1;
    int pointIndex = 1;
    while (pointIndex < this.points.length){							//copies from the original array into the temp Array. 
      if(this.alreadySeen(tempArray, this.points[pointIndex])){			//if the value was already copied , skips to the next value
        pointIndex = pointIndex + 1;
      }else{
        tempArray[tempIndex] = this.points[pointIndex];					//if the value was not copied, copies the value and then proceeds to the next value.
        pointIndex = pointIndex + 1;
        tempIndex = tempIndex + 1;
      }
    }
   
    
    ans = new Point[this.verticesLength(tempArray)];				
    for (int i = 0 ; i < ans.length ; i++){
      ans[i] = tempArray[i];
    }
    return ans;
  }  
   
 
 /**
  * The function alreadySeen checks if a given point is already present in the given array of points.
  * 
  * @param temp A given array of points
  * @param other The point we want to check
  *
  * @return if the given point is present returns true; if not returns false.
  */
  
  private boolean alreadySeen(Point[] temp, Point other){
    boolean ans = false;
    for (int i = 0 ; i < temp.length && temp[i] != null && !ans ; i++ ){		//goes over the Point array and compares it to the given point, if a match is found returns true
    	if (temp[i].equals(other)){
    		ans = true;
    	   }
    	}
    return ans;
  }
  
/**
 * The function verticesLength goes over a given array and determines the number valid entries it has.
 * For example , if an array in the size of 6 has only 2 entries the function would return 2.
 *   
 * @param temp the given array
 * @return The number of entries which are not null.
 */
  
  private int verticesLength (Point[] temp){
    int ans = 0;
    for (int i = 0 ; i < temp.length && temp[i] != null ; i++){
    	ans = i;
    	}
    return ans + 1;
  }
    
  
  
  /**
   * The method perimeter returns the perimeter of the polygon
   * @return a double data type representing the perimeter of the polygon
  */	   
  
  public double perimiter(){ 
    return this.perimeter;
  }
  
  
  /**
   * The private method perimeterPrivate calculates the perimeter of the polygon
   * @return a double data type representing the perimeter of the polygon
  */	  
  
  private double perimiterPrivate(){
    double ans = 0;
    for (int i = 0 ; i < this.actualVertices.length ; i++){
      if (i == this.actualVertices.length - 1){
        ans = ans + this.actualVertices[i].distance(this.actualVertices[0]);
      }else{
        ans = ans + this.actualVertices[i].distance(this.actualVertices[i + 1]);
      }
      
    }
    return ans;
  }
 
  
  
  /**
   * The method equals receives a polygon from the user and checks to see if that polygon is equal to the current one
   * Equality means if both polygon represent the same polygon
   * @param other a Polygon data type representing the polygon we receive from the user\
   * @throws Runtime exception if the point value is null
   * @return true if they are the same. Otherwise, false
  */	
 
  
  public boolean equals (Polygon p){
    boolean ans = false;
    if(p instanceof Polygon){
    	 if (this.actualVertices.length == p.actualVertices.length && this.perimeter == p.perimeter){
    	      ans = true;
    	    }
    }
    return ans;
  }
  
  
  
  /**
   * The method isVertex receives a point from the user and goes through the polygon to see if that point is a valid vertex
   * A valid vertex is a vertex where two adjacent points in the array are different
   * @param p a Point data type which represents the point we receive from the user
   * @return true if the point is a valid vertex. Otherwise, false
  */	  
  
  public boolean isVertex (Point p){
    boolean ans = false;
    if(p instanceof Point){
    	for (int i = 0 ; i < this.actualVertices.length && !ans ; i++){
    	      if (p.equals(this.actualVertices[i])){
    	        ans = true;
    	      }
    	    }
    }    
    return ans;
  }
    
  
  /**
   * The method translate moves the points that make up the polygon by adding the values of a point received by the user
   * @param p a Point data type representing the values to be added to each point of the polygon in order to "move" the polygon
  */	
  
  
  public void translate (Point p){            
    if(p instanceof Point){
      for(int i = 0; i<points.length ; i++){
        points[i].translate(p);
        }
      }
    }
  
  
  /**
   * The method toString inserts into a string all the points that make up the polygon
   * @return a String data type
  */	
 
  
  public String toString(){
    String ans = "Polygon: "+ "\n";
    for(int i=0; i<points.length; i++){
      if(points[i]!=null){
        ans= ans + "Point " + (i+1) + " : " + points[i] + "\n";
      }
    } 
    return ans;
     }
  
}  
  
